package org.infodavid.common.services;

import java.util.List;

import javax.persistence.PersistenceException;


import org.infodavid.common.model.criteria.IExtendedSearchCriteria;
import org.infodavid.common.persistence.IDataObject;
import org.infodavid.common.services.exceptions.IErrorHandler;
import org.infodavid.common.services.exceptions.ServiceException;
import org.infodavid.common.services.validators.IValidator;

/**
 * The Class IEntityService.
 * @param <L> The type of the entity view for list
 * @param <T> The type of the entity
 * @param <C> The type of the search criteria
 */
public interface IEntityService<L extends IDataObject<Long>,T extends L,C extends IExtendedSearchCriteria> {

	/** The ADD constant. */
	String ADD_ACTION = "ADD";

	/** The UPDATE constant. */
	String UPDATE_ACTION = "UPDATE";

	/** The REMOVE constant. */
	String REMOVE_ACTION = "REMOVE";

	/** The FIND constant. */
	String FIND_ACTION = "LIST";

	/** The GET constant. */
	String GET_ACTION = "GET";

	/**
	 * The Interface IInterceptorEvent.
	 */
	public interface IInterceptorEvent {

		/**
		 * Gets the context.
		 * @return the context
		 */
		IApplicationContext getContext();

		/**
		 * Gets the invoker.
		 * @return the invoker
		 */
		@SuppressWarnings("rawtypes")
		IEntityService getInvoker();

		/**
		 * Gets the action.
		 * @return the action
		 */
		String getAction();

		/**
		 * Gets the arguments.
		 * @return the arguments
		 */
		Object[] getArguments();

		/**
		 * Gets the results.
		 * @return the results
		 */
		Object[] getResults();

		/**
		 * Sets the results.
		 * @param values the results
		 * @return this
		 */
		IInterceptorEvent setResults(Object... values);
	}

	/**
	 * The Interface IInterceptor.
	 * @param <T> The type of the entity
	 */
	public interface IInterceptor<T extends IDataObject<Long>> {

		/**
		 * Pre execute.
		 * @param event the event
		 * @throws PersistenceException the persistence exception
		 * @throws ServiceException the service exception
		 */
		void preExecute(IInterceptorEvent event) throws PersistenceException, ServiceException;

		/**
		 * Post execute.
		 * @param event the event
		 * @throws PersistenceException the persistence exception
		 * @throws ServiceException the service exception
		 */
		void postExecute(IInterceptorEvent event) throws PersistenceException, ServiceException;

		/**
		 * Gets the next interceptor.
		 * @return the next interceptor
		 */
		IInterceptor<T> getNext();

		/**
		 * Sets the next interceptor.
		 * @param value the new next interceptor
		 */
		void setNext(IInterceptor<T> value);

		/**
		 * Adds an interceptor a the end.
		 * @param value the interceptor to add
		 */
		void add(IInterceptor<T> value);

		/**
		 * Removes the interceptor.
		 * @param value the interceptor to remove
		 */
		void remove(IInterceptor<T> value);

		/**
		 * Returns the first interceptor matching the given type.
		 * @param type the type of the interceptor
		 * @return the first interceptor matching the given type
		 */
		@SuppressWarnings("rawtypes")
		IInterceptor<T> getInterceptor(Class<? extends IInterceptor> type);
	}

	/**
	 * Creates the.
	 * @return a new instance
	 * @throws InstantiationException the instantiation exception
	 */
	T create() throws InstantiationException;

	/**
	 * Adds the entity.
	 * @param context the context
	 * @param value the new entity
	 * @return the key as long
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	long add(IApplicationContext context, T value) throws PersistenceException, ServiceException;

	/**
	 * Gets the entity using its key.
	 * @param context the context
	 * @param key the key
	 * @return the entity
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public abstract T get(IApplicationContext context, long key) throws PersistenceException,
	    ServiceException;

	/**
	 * Removes the entity.
	 * @param context the context
	 * @param key the key
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	void remove(IApplicationContext context, long key) throws PersistenceException, ServiceException;

	/**
	 * Update the entity.
	 * @param context the context
	 * @param value the entity
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	void update(IApplicationContext context, T value) throws PersistenceException, ServiceException;

	/**
	 * Gets the validator.
	 * @return the validator
	 */
	IValidator<T> getValidator();

	/**
	 * Gets the interceptor.
	 * @return the interceptor
	 */
	IInterceptor<T> getInterceptor();

	/**
	 * Gets the entities.
	 * @param context the context
	 * @param entities the entities
	 * @param criteria the search criteria
	 * @return the total number of entities
	 * @throws ServiceException the service exception
	 * @throws PersistenceException the persistence exception
	 */
	long findEntities(final IApplicationContext context, final List<L> entities, C criteria)
	    throws ServiceException, PersistenceException;

	/**
	 * Gets the error handler.
	 * @return the error handler
	 */
	IErrorHandler<? extends ServiceException> getErrorHandler();

	/**
	 * Sets the error handler.
	 * @param value the error handler
	 */
	void setErrorHandler(IErrorHandler<? extends ServiceException> value);
}
